#!/FACT/usr/local/bin/perl
# Debug Commands
# perl /FACT/USER/irag/dev/perl/mgtrans.pl -d ~/gen/files.i -p ~/gen/frprglist.txt -n -v  ~/gen/FR.app
# perl mgtrans-2.pl -d faf -p fap -n -v v71.i

=head1 NAME

B<mgtrans.pl> - Translate Magic PC v5.xx-v8.xx exported internal format files to a more readable and searchable format.

=head2 Features

=over 4

=item * Identifies and distinguishes multiple instances of fields.  

=item * Allows user-customized real field suffix (LNKREF=suffix definition).

=item * Prepends file names to real fields.

=item * Reads an ini (mgtrans.ini) to obviate setting command line parameters.

=item * Facilitates change management.

=item * Enables the use of configuration management tools.

=back 

=head1 SYNOPSIS

C<mgtrans [-hvnuf] [-s N] [-e N] [-p progist] [-d InternalFileExport] InternalProgramExport>

C<InternalProgramExport     output of Magic in internal format.>

For Detailed Help type: mgtrans -h

=head1 ARGUMENTS

=over

=item C<-p progList>

Unnecessary if you are using an application export.
Optional if you are converting one program and don't care that
none of the called programs are identified.  The lines in the
list have the same format as the Magic Document Export of
Programs Table of Contents.  Alternatively, it only requires
lines of the format:

       Program Name dd/dd dd:dd

There can be any text after the dd/dd and before the dd:dd or
after the dd:dd, where 'd' is a digit (0-9).  Formfeed
characters starting off lines will not be considered part of
the program name.

=item C<-d InternalFileExport>

Unnecessary if you are using an application export.
Optional if you are converting one program and don't care that
none of the real fields are identified.

=item C<-s>

Range Start.  For reporting on part of an application export.

=item C<-e>

Range End.    For reporting on part of an application export.

=item C<-v>

Verbose mode.  Gives progress report.

=item C<-f>

Indicates to use database file name prefixes for real fields.  The default
is not to use them.

=item C<-u>

Indicates to 'uniquify' variable names.  Default is to 'uniquify'.

=item C<-n>

Number the output files.

=item C<-m>

Get this manual page.

=item C<Alternative to command parameters>

In the same directory as the internal program export file, create an
B<mgtrans.ini> file having lines such as these:

   Verbose            = [0|1]
   numberFiles        = [0|1]
   uniquifyVars       = [0|1]
   useDfNamePrefixes  = [0|1]
   startProgram       = 999
   endProgram         = 999
   proglist           = FileSpec
   internalFileExport = FileSpec

These properties correspond to the options v, n, u, f, s, e, p, and d
respectively.

For logically valued fields, the value of '1' enables the property
and '0' disables.  Other fields take numeric or text arguments.

=back

=head1 EXAMPLES

=over

=item C<Sample call to convert an entire application using mgtrans.ini>

mgtrans /FACT/FACTRUN/FAP

=item C<Sample call to convert an entire application not using mgtrans.ini>

mgtrans -v -n -u -f /FACT/FACTRUN/FAP

=back 

=head1 BUGS

 insists on pulling files from somewhere when using application. maybe fixed.
 glob seems broken for NT, so we need full, not relative, pathnames.
 glob now fails on AIX.
 Fails when application has no data files defined.  Looks for external data dictionary. Workaround: Create empty file.

=head2 Planned Enhancements

 fix menus dump in version 8.
 verify expression needs stop or warning. put error, put warning.
 Defaults exclusion option- have one switch enable disable and section to use.-read user defaults in mgtrans.ini.  Not include task and flow parameters that are defaults.
 Specify the Magic.ini to be used in the mgtrans.ini file or on the command line.
 Clean up formatting of display blocks.
 When looking for brackets, strip record first of all strings.
 Add documenting of Reports - currently skipping RPR=\{ records.
 Debug Gotcha in FS 117 Debug LPR (LineView)
 Read MAGIC.INI to get '.eng' files. Allow it to be passed in on command line.
 Read .eng files for translation of Actions and Keyboard codes. Allow these to be passed in also.
 Read types fields . Allow passing in.

=head1 HISTORY

 09/18/98 Created from Epsilon reformatter
 10/02/98 Added support for incremental update mode.
 10/05/98 Bypass glob if it returns null.  On NT it seems to be broken. 
          Maybe I am missing a command line parameter. Whatever?
 10/05/98 Delete '=' signs following close paren in regexes. Worked in Unix, Not in NT.
 10/14/98 Added uniquify and datafile name prepending.
 10/15/98 Added pod suitable for text,html or manpage output.
 10/20/98 Force mgtrans.ini to start at first column. Fixed bug reading call_tsk args from version 6.00+,  Handle UDPs, Fix Put Warning.
          Stop writing blank lines for END_BLOCK and END_LNK.
 12/08/98 051 fix problem with Exit to: not supporting Version 8.
 12/09/98 052 fix problem with not pulling expression with embedded double quotes.

=head1 AUTHOR

Ira Gershenhorn E<lt>iragershenhorn@csi.comE<gt>

=cut

	print <<EOF;

     mgtrans - magic export format translater - version 0.52
     Copyright (C) 1998 Ira L. Gershenhorn
     
     mgtrans is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     as published by the Free Software Foundation; either version 2
     of the License, or (at your option) any later version.
     
     mgtrans is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

EOF

my $start1 = time;
my $start2;

my $ddloaded = 0;

my $compatibilityMode = 0;
my $mgMajorVers = 0;
my $mgMinorVers = 4;
my $versionDate = "10/15/1998";
my $copyrightLine = "mgtrans V$mgMajorVers.$mgMinorVers Copyright (c) 1998 Ira L. Gershenhorn & Co., Inc.";

my $generatingVB = 0;
use vars qw($opt_h $opt_n $opt_s $opt_e $opt_p $opt_d $opt_f $opt_u $opt_m);
use Getopt::Std;
use Pod::Usage;

#Getopt::Long::Configure('bundling');
#GetOptions('verbose|v' => \$verbose,
#		  'trace' => \$trace,
#		  'help|?|h' => \$help,
#		  'manual' =>  \$manual,
#		   'debug' => \$debug,
#		   'numberfiles|n' => \$numberfiles,
#		   'programdict|p' => \$programdict,
#		   'filedict|d' => \$filedict,
#		   'uniquify|u' => \$uniquify,
#		   'start|s' => \$start,
#		   'end|e' => \$end)
#  or pod2usage(2);


my $os = $ENV{OS};
my $ddPrefixSeparator = '.';

getopts( 'vnp:d:he:s:fum' );
if ($opt_h){  detailedUsage(); }
if ($opt_m){  manpage(); }
if( ! -f $ARGV[0] ){ $error = "main input file \"$ARGV[0]\" does not exist"; usage();}

my $lnkref = '';
my $rangeDir;
my $locateDir;
my $dbfile;
my $dbaccess;
my $dbshare;
my $dbopen;
my $dbcachesize;
my $fld;
my $pic;
my $strg;
my $attr;
my $siz;
my $mdfy;
my $trns;
my $def;
my $mod;
my $ctrl;
my $null;
my $selectionTask;
my $cnf;
my $sloc;
my $sfail;
my $lstrg;
my $sufix;
my $updateDate;
my $updateTime;
my $progName;
my $outfile;
my $indentLevel;
my $indentExp = 'Y';
my $indentLevelPrev;
my @indentExp;


#default property values
my $defTaskType = 'Online';
my $defTaskMode = 'Modify';

my $defSelectionTask	= 'No';
my $defIsResident	= 'No';
my $defOpenTaskWindow	= 'Yes';
my $defCloseTaskWindow	= 'Yes';
my $defForegroundWindow	= 'Yes';
my $defRefreshWindow	= 'No';

my $defFormRecords = 0;
my $defFlip	= 'Y';#??
my $defAllowCycleRecordMain	= 'Yes';
my $defConfirmUpdate	= 'No';
my $defLocateExp	= '0';
my $defLocateDir	= 'Ascending';

my $defRangeExp	= '0';
my $defRangeDir	= 'Ascending';
my $defTaskEndTaskCondition	= 'No';
my $defTaskEndCheck	= 'Before entering record';
my $defSufix	= 'No';
my $defTaskForceRecordDelete	= 'No';
my $defAort =

my $defLstrg	= 'On Modify';
my $defSloc	= 'Y';
my $defSfail	= 'Y';

#Options Control

my $defAllowOptions	= 'Yes';
my $defAllowModify	= 'Yes';
my $defAllowCreate	= 'Yes';
my $defAllowDelete	= 'Yes';
my $defAllowQuery	= 'Yes';
my $defAllowLocate	= 'Yes';
my $defAllowRange	= 'Yes';
my $defAllowKeyChange	= 'Yes';
my $defAllowSorting	= 'Yes';
my $defAllowIOFiles	= 'Yes';
my $defAllowAbort	= 'Yes';
my $defAllowKeyOpt	= 'Yes';
my $defAllowLocateInQuery	= 'Yes';
my $defAllowReports	= 'No';

my $defQueryRight	= 'Y';
my $defModifyRight	= 'Y';
my $defDeleteRight	= 'Y';
my $defExecuteRight	= 'Y';


#some lookup tables
$flowMode{S} = 'Step';
$flowMode{F} = 'Fast';
$flowMode{C} = 'Combined';
$flowMode{B} = 'on Zoom (Before)';
$flowMode{A} = 'on Zoom (After)';
$flowDir{F} = 'forward';
$flowDir{C} = 'forward,back';
$flowDir{B} = 'backwards';

$initialTaskMode{M} ='Modify';#verified
$initialTaskMode{C} ='Create';#verified
$initialTaskMode{D} ='Delete'; #verified
$initialTaskMode{E} ='Query';#verified
$initialTaskMode{P} ='As Parent';#verified
$initialTaskMode{L} ='Locate';
$initialTaskMode{R} ='Range';
$initialTaskMode{K} ='Key';
$initialTaskMode{S} ='Sort';
$initialTaskMode{O} ='Files'; #verified
#$initialTaskMode{N} ='Options';#verified

#tab string

$tabstr = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
$spacestr = "                                                                                                                                               ";

print STDOUT "...loading dictionary\n" if $opt_v;


my $file = glob($ARGV[0]);
if ($file eq '' && $ARGV[0] ne '') {
  $file = $ARGV[0];
}
read_mgtrans_ini();

if (defined ($ini{lc(Verbose)           })){ $opt_v = $ini{lc(Verbose)};  }
if (defined ($ini{lc(numberFiles)       })){ $opt_n = $ini{lc(numberFiles)};}
if (defined ($ini{lc(uniquifyVars)      })){ $opt_u = $ini{lc(uniquifyVars)};}
if (defined ($ini{lc(useDfNamePrefixes) })){ $opt_f = $ini{lc(useDfNamePrefixes)};}

if (defined ($ini{lc(startProgram)      })){ $opt_s = $ini{lc(startProgram)}; }
if (defined ($ini{lc(endProgram )       })){ $opt_e = $ini{lc(endProgram)}; }
if (defined ($ini{lc(progList)          })){ $opt_p = $ini{lc(progList)}; chomp($opt_p)}
if (defined ($ini{lc(internalFileExport)})){ $opt_d = $ini{lc(internalFileExport)}; chomp($opt_d) }


my $useDfNamePrefixes = defined($opt_f);#default is not to prepend
my $uniquifyVars = !defined ($opt_u);#default is to uniquify

my @dd = ();
if ($opt_d) {
	if ( glob($opt_d)  ne '') {
	$opt_d = glob($opt_d);
    }
}




if( $opt_d ){
	$ddfile = $opt_d;
}
else{
	$ddfile = '/FACT/FACTRUN/FAF';
}
if( ! -f $opt_d ){ $error = "option d:file \"$opt_d\" does not exist"; usage();}
print STDERR "pulling file definitions from $ddfile\n" if $opt_v;
print STDERR "prefixing datadictionary names\n" if $opt_f && $opt_v;

print STDOUT "...first pass. loading variables and expressions\n" if $opt_v;

open IN, "< $file ";
loadExpressions();
close IN;
close MENUS;
close DROPMENUS;

print STDOUT "...second pass. writing doc files\n" if $opt_v;
$start2 = time;

open IN, "< $file ";
readin();

if (/^VRSN=(\d+)/) {
	$magicVersion = $1;
}
else{ die "no VSRN?\n";
}
$p = 0;
$indentUsed = 1;

while (readin()) {
	if ($_ eq "PRG={\n") {
		last if (defined($opt_e) && $p >$opt_e );
		writeProgram();
	}
}
close IN;

print STDERR "Total Run times (secs), pass1:", $start2 - $start1 . ' pass2:', time - $start2 ;

# exit here
sub varDesc {
	my $id = shift;
	my $h = $hier;
	my $desc = '?var?';

	while (1) {
		if (defined($var[$p]->{$h}->{$id}->{desc})) {
			$desc = $var[$p]->{$h}->{$id}->{desc};
			last;
		}
		elsif ($h eq '1' ) {
			last;
		}
		else {
			$h =~ s/(\.\d+)$//;   #remove one level
		}
	}
	$desc;
}
sub expandedExpression{
	my $in = shift;
	my $lastToken = 'none';
	my $result = '';
	while ($in =~ m{
			 (
			 \'\'           | # null string
			 \'[^\']*?\'    | # strings
			 IF\s\( |
			 \sOR\s |
			 \sAND\s |
			  <> |
			  <= |
			  >= |
			 [&<>\.\-+*,=\(\)\/] | # punctuation
			 [A-Z]+         | # symbols
			 [0-9]+
			 )
		   }xg){
		$token = $1;
		if ( $token =~/IF\s\(/){
			$lastToken = 'if';			    $result .= $token . ' ';
		}
		elsif ( $token =~/\s(OR|AND)\s/){
			$lastToken = 'and-or';			    $result .= $token;
		}
		elsif ( $token =~/\'[^\']*?\'/){
			$lastToken = 'string';			$result .= $token;
		}
		elsif ($token =~ /[&<>+*,=\'\(\)\/]/){
			if (($lastToken eq 'string') && ($token eq '&')) {
				$result .= ' ';
			}
			$lastToken = 'punct';			$result .= $token . ' ';
		}
		else{
			if ($lastToken eq 'string'){
				$lastToken = 'const';		$result .= $token;
			}
			else{
				if ( $token =~ /^[A-Z]{1,2}$/){
					$lastToken = 'var';		$result .= varDesc($token) . ' ';
				}
				else{
					$lastToken = 'keyword';	$result .= $token . ' ';
				}
			}
		}
	}
	$result;
}
sub countBrackets{
	my $count;
	my $rights = 0;
	my $lefts = 0;

	$prevline =~ s/".*?"//g;  #strip out strings so we don't get fooled by brackets inside the strings.
	while ($prevline =~ m/(\}+),/g){
		$rights += length $1;
	}
	while ($prevline =~ m/=(\{)/g){
		$lefts += length $1;
	}
	$count = $rights - $lefts;
}
sub	setHierarchicalPosition{
# EXP: no brackets => subtask, 1 => close current task and next task is on the same level. 2+ => level after ascending n-1 levels.
# TXT, ACTV, BLOCK: a surfeit of 1 bracket will close the preceding DSP. That's expected.  Any more close previous tasks.
# OLECLASS: surfeit of 1 bracket: closes prior DIT_INFO, 2: closes prior ITM, 3: closes prior DSP
# PIC (version 5): surfeit of 1 closes prior ITM, 2: closes prior DSP.
#
	$length = countBrackets();
	$length -= 1 if ($prevline =~ /^(ACTV|TXT|BLOCK)/);
	$length -= 2 if ($prevline =~ /^(PIC)/);
	$length -= 3 if ($prevline =~ /^(OLECLASS)/);
	if ( $length == 0) { #add a level
		$hier .= '.1';
	}
	elsif ($length >= 1 && $hier eq '1') {
		print STDOUT "gotcha\n";
	}
	elsif ($length == 1) {
		$hier =~ s/(\d+)$/$1+1/e;   #move laterally, increment the last number
	}
	else { #move up then over
		$hier = getTaskHier( $length-1 );
		$hier =~ s/(\d+)$/$1+1/e;
	}
}
sub initTaskVarsPrescan{#for prescan
	$formNumber=0;
	$e=1;
	$j=1;
	$v=1;
	$maindbf=0;
}
sub loadExpressions{
	$e = 1;
	$loading = 'nothing';
	while (<IN>){
#		s/ISN(_2)?=\d+,?//;  # version 8 may have optional ISN numbers we don't need. strip them out.
		if (!/^TSK/) {		#unique to PROGRAMS section
			$prevline = $_;
		}
		if (!/^[DEFHKLMPRST]/) {
			next;
		}
		if (/^EXP="(.*)"[,\}]/){ #unique to PROGRAMS section-match as much as possible
			$exp[$p][$t][$e] = expandedExpression($1);
			$e++;
		}
		elsif ( /^KEY=\{DESC=\"(.*?)\",/){#unique to FILES section
			ddKey($1);
		}
		elsif (/^RMRK=/){
			if ( /LNKREF=(\w+)/) {
				$lnkref = '_' . $1;
			}
		}
		elsif ( /^FILE=\{(DESC|NAME)/){#unique to FILES section and there was an '=' sign on the end . Worked in Unix, Not in NT
			$loading = 'files';
			ddFile();
		}
		elsif (/^FLD=\{DESC=\"(.*?)\",/) {
			if ($loading eq 'files') {
				ddField($1);
			}
			else {
				$virt[$p][$t][$v]->{desc}= $1;
				$virt[$p][$t][$v]->{pic} = $1 if $_ =~ /PIC="(.+?)"/;
#				$virt[$p][$t][$v]->{strg} = $1 if $_ =~ /STRG=(\d+)/;
				$attr = $1 if $_ =~ /ATTR=(.)/;
				$virt[$p][$t][$v]->{type}  = $1 if $_ =~ /TYP=([0-9]+),/;
				$virt[$p][$t][$v]->{range} = $1 if $_ =~ /RNG="(.+?)",/;

				$virt[$p][$t][$v]->{attr} = expandIOmode( 'attr', $attr);
				$v++;

#				$attr= $1 if $_ =~ /SIZ=(\d+)/;
#				$siz = $1 if $_ =~ /RSRCE=\{MDFY=(.)/;
#				$mdfy= $1 if $_ =~ /TRNS=(.)/;
#				$trns= $1 if $_ =~ /DEF=(.)/;
#				$def = $1 if $_ =~ /MOD=(.)/;
#				$mod = $1 if $_ =~ /CTRL=(.)/;
#				$ctrl= $1 if $_ =~ /CTRL_STP="(.+?)"/;
#				$null= $1 if $_ =~ /NUL_ALW=(.)/;
			}
		}
		elsif (/^SLCT={NAME="([A-Z]+)",/){
			$varletter = $1;
			my $desc;

			if (/FLD=(\d+),MOD=V,/){
				$desc = $virt[$p][$t][$1]->{desc};
				$var[$p]->{$hier}->{$varletter}->{type} = 'Virt';
				$var[$p]->{$hier}->{$varletter}->{'ref'} = \$virt[$p][$t][$1];
			}
			elsif (/FLD=(\d+),MOD=R,/){
				if (defined($dd[$dbf]{fields}->[$1])){
					my $ddPrefix = '';
					if ( $useDfNamePrefixes ){
						$ddPrefix = $dd[$dbf]{desc} . $ddPrefixSeparator
					}
					$desc = $ddPrefix . $dd[$dbf]{fields}->[$1];
					$var[$p]->{$hier}->{$varletter}->{type} = 'Real';
				}
				else{
					$desc = '?undefined';
				}
			}
			my $varSuffix = '';
			if ($lnkref ne '') {
				$lnkref = $lnkref;
			}
			if ($uniquifyVars){
			    my $i=0;
				while ($var[$p]->{vars}->{$desc . $lnkref . $varSuffix}){
					$i++;
					$varSuffix = '_' . $i;
				}
			}
			$desc .= $lnkref . $varSuffix;
			$var[$p]->{$hier}->{$varletter}->{desc} = $desc;
			$var[$p]->{vars}->{$desc } = 1;
		}
		elsif (/^LNK=\{DB=(\d+)/){
			$dbf = $1;
		}
		elsif (/^END_LINK/){
			$dbf = $maindbf;
			$lnkref = '';
		}
		elsif (/^DB/) {
			$maindbf = $1 if $_ =~ /DB=(\d+)/;
			$dbf = $maindbf;
		}
  	    elsif (/^HDR=\{DESC="(.+?)",/) {
			print STDOUT "..... $p.$1\n" if ( $opt_v && $hier eq '1');
			if (!$opt_p || $hier ne '1') {
				$prgtaskName[$p]->{$hier}->{desc} = $1;
				$prgtaskName[$p]->{$hier}->{idx} = $t;
			}
		}
		elsif ( $_ eq 'RPR={' ){ # in report, similar to task structure, skip it.
			while (<IN>){
				if (/^PRG=/){
					unshift @saved, $_;
					last;
				}
			}
		}
		elsif (/^TSK=/){
			$t++;
			initTaskVarsPrescan();
			setHierarchicalPosition();
#			print STDOUT "hier = $hier\n";
		}
		elsif ($_ eq "PRG={\n"){
			if ($loading eq 'nothing') { #This must be a single program export. We need to load a program list
				if ($opt_p) {
				  if ( glob ($opt_p) ne '' ){
					$opt_p = glob($opt_p);
	  			   }
				}
				else {
					$opt_p = '/FACT/FACTRUN/FAP';
				}
				if(  ! -f $opt_p ){ $error= "option p:file \"$opt_p\" does not exist."; usage();}
				readPrgList($opt_p);
			}
			$loading = 'programs';
			if (!$ddloaded) {
				loadDataDictionary();
			}
			initTaskVarsPrescan();
			$p++;
			$t=1;
			$hier='1';
		}
		elsif (/^DSP(?:_INFO)?=\{NAME="(.*?)",/) {#version 8 has the _INFO string
			$formNumber++;
			$prgtaskName[$p]->{$hier}->{form}->[$formNumber] = $1;
		}
		elsif (/^RGHT=\{NAME="(.*?)",KEY="(.*?)",PBLC=(.)/) {
			$loading = 'rights';
			$opt_p = 0; # Disable reading programs from separate table if we have the whole application here.
			$rights++;
			$rights[$rights]->{name} = $1;
			$rights[$rights]->{key}  = $2;
			$rights[$rights]->{public}= $3;
		}
		elsif (/^xMENU=\{/) { #. - version 8.xx +  - not working yet.
			$loading = 'menus';
 			if (!defined $dropmenus) {
				$indentUsed = 1;
				$dropmenus = 1;
				open DROPMENUS, ">Menus.txt";
				select DROPMENUS;
				print "\nMenus\n";
			}
			printMenuEntry();
		}
		elsif (/^DRPD=\{/) { #DRPD lines come at the end of an internal dump so we can reconcile them on the first pass. - version 5.xx only
			$loading = 'dropmenus';
 			if (!defined $dropmenus) {
				$indentUsed = 1;
				$dropmenus = 1;
				open DROPMENUS, ">dropdownMenus.txt";
				select DROPMENUS;
				print "\nDrop-down Menus\n";
			}
			printMenuEntry();
		}
		elsif (/^MNU=\{/) { #MNU lines come at the end of an internal dump so we can reconcile them on the first pass.  - version 5.xx only
			$loading = 'popmenus';
 			if (!defined $menus) {
				$indentUsed = 1;
				$menus = 1;
				open MENUS, ">popupMenus.txt";
				select MENUS;
				print "\nPop-up Menus\n";
			}
			printMenuEntry();
		}
#		elsif (/^OLECLASS=\{/) {
#			$x = 1;
#		}
	}
}
sub spaceTo{
	my ($current, $to) = @_;
	$spacing = ($current < $to)?($to-$current):1;
	print substr ($spacestr, 0, $spacing);
	$current += $spacing;
	$current;
}
sub printMenuEntry{
	tabOut();
	$rpos = 4 * $indentUsed;

	($type) = $_ =~ /TYP=(.)/;

	$desc = '';
	$prog = 0;
	$ext  = '';
	$actv = 0;
	$char = 0;

	$prog = $1 if /PRG=(\d+)/;
	$actv = $1 if /ACTV=(\d+)/;#action - see act_std.eng
	$desc = $1 if /DESC="(.*?)",/;
	$ext  = $1 if /EXT="(.*?)",/;
	$char = $1 if /CHAR=(\d+)/;

	if ($type eq 'L' ){#exits, menus, program, system types all have desc fields, only the line doesn't.
		$desc = '----------------------------------------';
	}
	print $desc;	$rpos += length($desc);
	$rpos = spaceTo($rpos, 60 );
	print "|"; $rpos++;
	$desc = '';
	if ($type eq 'E' ){#exit
		$desc = $ext;
	}
	elsif($type eq 'P' ){#program
		$desc = $prgtaskName[$prog]->{'1'}->{desc};
	}
	if ($desc ne '') {
		print $desc;	$rpos += length($desc);
	}
	$rpos = spaceTo($rpos, 100 );
	print '|';
	print  rights($1) if (/GRP=(\d+)/);
	print "\n";
	readin();
	($brackets) = $_ =~ /(\}+)$/;
	$indentUsed -= length($brackets) - 2;
}
sub rights{
	my $i = shift;
	if (defined($rights[$i]->{name})) {
		$name = $rights[$i]->{name};
	}
	else {
		$name = '?error?';
	}
	$name;
}
sub initDataDictionary{
	$ddloaded = 1;
	$ddfile = 0;
	$dd[0]{desc}= 'None';
	$dd[0]{desc}= '0.' if $compatibilityMode;
	$dd[0]{key}->[0]= 'None';
	$dd[0]{key}->[0]= '0.' if $compatibilityMode;
}
sub ddFile{
	if (!$ddloaded) {
		initDataDictionary();
	}
	$desc = $1 if /DESC=\"(.*?)\"/;
	$name = $1 if /NAME=\"(.*?)\"/;#eg DEBUG.DAT for the DBG file
	$ddfile++;
	$ddfield = 0;
	$ddkey = 0;
	$dd[$ddfile]{desc}= $desc;
	$dd[$ddfile]{key}->[0]= 'None';
	$dd[$ddfile]{key}->[0]= '0.' if $compatibilityMode;
}
sub ddField{
	my $desc = shift;

	$ddfield++;
	$dd[$ddfile]{fields}->[$ddfield]= $desc;
}
sub ddKey {
	my $desc = shift;
	$ddkey++;
	$dd[$ddfile]{key}->[$ddkey]= $1;
}
sub loadDataDictionary{
	open( DD, "< $ddfile");
	while (<DD>){
		if ( /^FILE=\{/){
			ddFile();
		}
		elsif ( /^FLD=\{DESC=\"(.*?)\",/){
			ddField($1);
		}
		elsif ( /^KEY=\{DESC=\"(.*?)\",/){
			ddKey($1);
		}
	}
	close DD;
}



sub nextVar
{
	$currentVar++;
	my $highChar = $currentVar/26;
	my $lowChar = $currentVar % 26;

	my $highCharA = ($highChar==0)?'':chr($highChar+65);
	my $lowCharA = chr($lowChar+65);
	$currentVarA = $highCharA . $lowCharA;
}
sub tabOut{
	print substr $tabstr, 0, $indentUsed;
}
sub getWrtRead{
	my $dir = shift;

	($mode, $io, $dsp) = $_ =~ /MOD=(.),IO=\{(.+?)\},DSP=\{(.+?)\}/;
	$ioTsk = 0;
	$dspTsk = 0;
	$ioIdx = 0;
	$dspIdx = 0;
	$ioTsk  = $1 if $io  =~ /TSK=(\d+)/;
	$ioIdx  = $1 if $io  =~ /IDX=(\d+)/;
	$dspTsk = $1 if $dsp =~ /TSK=(\d+)/;
	$dspIdx = $1 if $dsp =~ /IDX=(\d+)/;

	$ioHier = getTaskHier( $ioTsk );
	$dspHier = getTaskHier( $dspTsk );

	$dsp = $prgtaskName[$p]->{$dspHier}->{form}->[$dspIdx];

	$io = $prgtaskName[$p]->{$ioHier}->{form}->[$ioIdx];
	$format = expandIOmode('ioformat', $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{'format'});
	$media =  expandIOmode('iomedia',  $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{media});
	$access = expandIOmode('mod',      $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{access});

	print "$dir Form: $dsp ON \"$prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{desc}\" $media  $access  $format  File: $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{file}";

}
sub getTaskHier {
	my $levels = shift;
	my $x = $hier;

	while ($levels > 0) {
			$x =~ s/(\.\d+)$//;   #remove one level
			$levels--;
		}
	$x;
}

sub doView{

	while (readin()){
		if (/^(SUFIX|PRFIX|VIEW|BRK|DSP)/){
			unshift @saved, $_;
			last;
		}
		$indentUsed = $indentLevel if ! /^RMRK/;
		if ( /^(SLCT|LCT|RNG|RMRK|STP|LNK|END_LINK|BLOCK||CALL_TSK|EXE|UPD|WRT|READ|SCN|EXT)/){
			tabOut();
		}
		else{
			unshift @saved, $_;
			last;
		}
		if (/^CALL_TSK/ && ! /FLW=\{/) {  # flow not part of call, then are args
			getArgsAndFlow();
		}
		if (/^SLCT/     && ! /FLW=\{/) {  # flow not part of select
			$orig = $_;
			undef @lsaved;
			for ($i=1; $i<=2; $i++){
				readin();
				if (/^(LCT|RNG)/){
					push @lsaved, $_;
					if (/FLW=\{/){
						chomp($orig);
						$_ = $orig . $_;
						last;
					}
				}
				else{
					push @lsaved, $_;
					$_ = $orig;
					last;
				}
			}
			unshift @saved, @lsaved
		}
		$flowStr = '';

		if (/FLW=\{/){
			$isBlock    = $_ =~ /^BLOCK=/;
			$isSelect   = $_ =~ /^SLCT=/;
			( $flwCond, $flowMode, $flowDir ) = $_ =~ /CND=(Y|N|\d+),MOD=(.),DIR=(.)/;

			if ( $taskFlow eq 'Online' ){
				if ( $flowMode !~ /S|F|C|B|A/) {$flowStr  = 'unknown mode';			        }
				else {					  	    $flowStr  = "\t// " . $flowMode{$flowMode};	}
				if ( $flowDir  !~ /F|C|B/  )   {$flowStr .= ' unknown dir';  		        }
				else { 				 		    $flowStr .= ' '     . $flowDir{$flowDir};	}

			}
			if ( $flwCond eq 'Y' ){
				$indentExp = 'Y';
				if ($isBlock){
					$indentLevel++;
					print "Do\n";
					tabOut();
				}
				elsif ($indentExp ne 'Y' ) {
					$indentLevel--;
					$indentExp = 'Y';
				}
			}
			else{
				if ($flwCond ne 'N') {
					if (defined(   $exp[$p][$t][$flwCond])){
						$flwCond = $exp[$p][$t][$flwCond];
					}
					else{
						$flwCond = '?undefined?';
					}
				}
				$indentLevel++;
				$indentUsed = $indentLevel;
				if ( $indentExp ne $flwCond ){
					$indentExp = $flwCond;
					if ( $flwCond eq 'N' ){
						if ($isSelect){
							print "Never do/Land on fields:\n";
							tabOut();
						}
						else {
							print "Never do:\n";
							tabOut();
						}
					}
					else{
						print "If $flwCond\n";
						tabOut();
					}
				}
				else{ #not a new condition
					print "\t";
				}
				$indentLevel-- if ! $isBlock;
			}
		}
		if (/^SLCT=\{NAME="([A-Z]{1,2})"/){
			print "$var[$p]->{$hier}->{$1}->{type}:$var[$p]->{$hier}->{$1}->{desc}";
			if (/ASS=(\d+)/){
				print "\t=\t$exp[$p][$t][$1]";
			}
		}
		elsif (/^RMRK="(.*?)",/){
			if ( $1 eq ''){
				print "//-------------------------------------------------------------------------";
			}
			else{
				print "// $1";
			}
		}
		elsif (/^CALL_TSK=/){
			($mode, $task, $lock) = $_ =~ /MOD=(.),TSK=(\d+),LOCK=(.)/;
			print "Call Prog: $prgtaskName[$task]->{'1'}->{desc}"  if $mode eq 'P';
			print "Call Task: $prgtaskName[$p]->{$hier . '.' . $task }->{desc}" if $mode eq 'T';
			print "Call Exp: $exp[$p][$t][$task]"      if $mode eq 'E';
			print "Call UDP: $exp[$p][$t][$task]"      if $mode eq 'U';
			if (defined(@args))	{
				print "$flowstr";
				$i = 1;
				foreach $arg (@args){
					print "\n";
					tabOut();
					printf( "\t% 3d|%s", $i, $arg);
					$i++;
				}
				$flowstr = '';
				undef(@args);
			}
		}
		elsif (/^STP=/){
			print "Put Warning " if $_ =~ /MOD=(V|W)/;
			print "Put Error   " if $_ =~ /MOD=E/;

			print $1 if $_ =~ /TXT="(.*?)",/;
			print $exp[$p][$t][$1] if $_ =~ /EXP=(\d+)/;
		}
		elsif (/^LNK=/){
			$db = 0;
			$key = 0;
			$dir = '';
			$cls = 0;
			$views = 0;
			$view = 0;
			$mod = 0;
			$rtrn ='';

			$db    = $1 if /DB=(\d+)/;
			$key   = $1 if /KEY=(\d+)/;
			$dir   = $1 if /DIR=(.)/;
			$cls   = $1 if /CLS=(\d+)/;
			$views = $1 if /VIEWS=(\d+)/;
			$view  = $1 if /VIEW=(\d+)/;
			$mod   = $1 if /MOD=(.)/;
			$rtrn  = $1 if /RTRN="(.+)"/;


			print "Link ";
			if    ($mod eq 'R'){ print "Query   ";  }
			elsif ($mod eq 'W'){ print "Write   ";  }
			elsif ($mod eq 'N'){ print "Validate";  }
			elsif ($mod eq 'A'){ print "Create  ";  }
			print " : $db $dd[$db]{desc}  Key: $key $dd[$db]->{key}->[$key]  Dir: $dir";
			my $var = varDesc $rtrn;

			print "   Returning: $var"  if $rtrn ne '';

			$indentLevel++;
		}
		elsif (/^END_LINK,/){
			$indentLevel--;
			$lnkref = '';
		}
		elsif (/^BLOCK=/){
		}
		elsif (/^END_BLK/){
			$indentLevel--;
		}
		elsif (/^EXE=\{EXP=(\d+)/){
			$exp =  $1;
			print "$exp[$p][$t][$1]";
		}
		elsif (/^UPD=/){
			($fld, $exp, $mode, $abort ) = $_ =~ /FLD="(.+)",EXP=(\d+),MOD=(.),ABRT=(.)/;
			$inc = ( $mode eq 'I' )?'+':'';
			print varDesc($fld) . "\t$inc=\t$exp[$p][$t][$exp]";
			if ( $complete) {
				print "\t//$mode,$abort";
			}
		}
		elsif (/^WRT=/){
			getWrtRead( 'Output' );
		}
		elsif (/^READ=/){
			getWrtRead( 'Input' );
		}
		elsif (/^SCN=/){
			$exp = 0;
			$dsp = 0;
			$mod = '';
			$edit = '';
			$exp = $1 if /EXP=(\d+)/;
			$dsp = $1 if /DSP=(\d+)/;
			$mod = $1 if /MOD=(.)/;
			$edit = $1 if /EDIT=(.)/;
			$edit = $edit eq 'S'?'Scan':'Edit';
			print "Browse $edit $exp[$p][$t][$exp]";
		}
		elsif (/^EXT=/){
			$exp='';
			$clr='';
			$wait='';
			
			($exp) = $1 if $_ =~ /EXP=(\d+)/;
			print "Exit to: $exp[$p][$t][$exp]";
			if ( $_ =~ /CLR=(.)/){
				if ($1 == 'Y') {
					print " and clear the screen";
				}
				else {
					print " and do not clear the screen";
				}
			}
			if ( $_ =~ /WAIT=(.)/) {
				if (!defined ($ini{lc(defExitToWait)}) ) {
					$ini{lc(defExitToWait)} = '';
				}
				if ($1 == 'Y') {
					print " and wait for completion" if $ini{lc(defExitToWait)} != 'Y';
				}
				else {
					print " and do not wait for completion" if $ini{lc(defExitToWait)} != 'N';
				}
			}
		}
		elsif (/^LCT=/){
			$min ='';
			$max ='';
			$min = $1 if $_ =~ /MIN=(\d+)/;
			$max = $1 if $_ =~ /MAX=(\d+)/;
			if ($min ne '')	{ 
				print "\tLocate From: $exp[$p][$t][$min]";
				if ($max ne ''){
					print "\n";
					tabOut();
				}
			}
			print "\tLocate   To: $exp[$p][$t][$max]" if $max ne '';
		}
		elsif (/^RNG=/){
			$min ='';
			$max ='';
			$min = $1 if $_ =~ /MIN=(\d+)/;
			$max = $1 if $_ =~ /MAX=(\d+)/;
			if ($min ne '')	{
				print "\tRange From: $exp[$p][$t][$min]";
				if ($max ne ''){
					print "\n";
					tabOut();
				}
			}
			print "\tRange   To: $exp[$p][$t][$max]" if $max ne '';
		}
		print "$flowStr\n" if (!/^END_(BLK|LINK)/ );
	}
}
sub	doBreak{
	$context = 'Record';
	while (readin()){
		$indentLevel = 1;
		$indentExp = 'Y';
		if (/^VIEW=/){
			print "\nOperations: $context Main\n";
			doView();
		}
		elsif (/^PRFIX=/){
			print "\nOperations: $context Prefix\n";
			doView();
		}
		elsif (/^SUFIX=/){
			print "\nOperations: $context Suffix\n";
			doView();
		}
		elsif (/^(DSP|DRPD)/) { # there was an '=' sign on the end . Worked in Unix, Not in NT
			unshift @saved, $_ ;
			last;
		}
		elsif (/^BRK/) {
			if (/FLD="([A-Z]+)"/) {
				$context = 'On Change of ' . $var[$p]->{$hier}->{$1}->{desc} ;
			}
			else {
				$context = 'Task';
			}
		}
	}
}
sub doFlow{
	while (readin()){
		if (/^BRK/){
			doBreak();
		}
		elsif (/^(DSP|DRPD)/) { # there was an '=' sign on the end . Worked in Unix, Not in NT
			unshift @saved, $_ ;
			last;
		}
	}
}


format FORM_DETAIL_L =
 @<<<<<:                        @<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @>>> @>>> @>>> @<<< @>>>>
 $item,                       $attr,$pic,    $picExp,               $row, $col,$rows,$cols,$allowInput
      @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      $it
.

format FORM_DETAIL_S =
#      +-------- Name -------+Attr+-- Pic --+--------Pic-Exp--------+-Row+-Col+Rows+Cols+Allow+\n";
 @<<<<<: @<<<<<<<<<<<<<<<<<<<<< @<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @>>> @>>> @>>> @<<<  @>>>>
 $item,   $it  ,              $attr,$pic,    $picExp,                $row,$col,$rows,$cols,$allowInput
.

format FORM_STATICS =
 @<<<<<<<<<: @<<<<<<<<<<<<<<<<<<<<< at:  @>>>, @>>> dimension: @>>>, @>>>>
 $item,      $pic,                  $row,$col,             $rows,$cols
.

sub pickUpCommonDisplayFields {

	$col = '';	$row = '';	$rows = '';	$cols = '';	$color = '';  $attr = ''; $editType = '';

	$col   = $1 if /X=(\d+)/;
	$row   = $1 if /Y=(\d+)/;
	$cols  = $1 if /DX=(\d+)/;
	$rows  = $1 if /DY=(\d+)/;
	$color = $1 if /COLOR=(\d+)/;
	$attr  = expandIOmode('attr', $1) if /ATTR=(.),/;
	$editType  = expandIOmode('editControl', $1) if /TYPE=(.),/;
}
sub	doDisplay{
	my $formNumber = 0;
	print "\nDisplay Items\n\n";
	print "      +-------- Name -------+Attr+-- Pic --+--------Pic-Exp--------+-Row+-Col+Rows+Cols+Allow+\n";
	while (readin()){
		if (/^FRM/){
		}
		elsif (/^BLOCK/){
		}
		elsif (/^ACTV/){
		}
		elsif (/^ITM=/){
			undef $fld;
			$fld = $1 if /FLD="(.+?)"/;
			if ($magicVersion <= 599 ){
				pickUpCommonDisplayFields();
			}
			if (defined($fld)) {
				$it =  varDesc($fld);
				$item = 'Field';
			}
			else {
				$item = 'Expr';
			}
		}
		elsif (/^DBOX=/) {	#version 600+
			pickUpCommonDisplayFields();
		}
		elsif (/^DIT_INFO=/) {	#version 600+
			$clr = 0; $font = 0; $style = 0; $misc = 0; $align = 0; $para_align = 0; $dit_name = ''; $isn = 0; $static=0;

			$clr      = $1 if /CLR=\d+/;
			$font     = $1 if /FONT=\d+/;
			$style    = $1 if /STYLE=\d+/;
			$misc     = $1 if /MISC=\d+/;
			$align    = $1 if /ALIGN=\d+/;
			$para_align = $1 if /PARA_ALIGN=\d+/;
			$dit_name = $1 if /DIT_NAME="(.*?)"/;
			$isn      = $1 if /ISN=\d+/;
			$static   = $1 if /STATIC=\d+/;

			if    ($editType eq 'Static'){
				if    ($static == 1     ){ $editType = 'Rectangle';	}
				elsif ($static == 4     ){ $editType = 'Ellipse';	}
				elsif ($static == 8     ){ $editType = 'Line';	}
				elsif ($static == 128   ){ $editType = 'Group';	}
				else  { 				   $editType = 'Text';	}
			}
			elsif ($editType eq 'Slider'){
				if    ($style & 16384   ){ $editType = 'VertSlider'; }
				else                     { $editType = 'HorizSlider';	 }
			}
			elsif ($editType eq 'Radio'){
				if    ($style & 256     ){ $editType = 'Radio'; }
				elsif ($style & 512     ){ $editType = 'ComboBox'; }
				elsif ($style & 1024    ){ $editType = 'Tab'; }
				elsif ($style & 32768   ){ $editType = 'ListBox'; }
			}
		}
		elsif (/TXT="(.+?)"/ || /^OLECLASS/) {	#was simply /^TXT=/ but made more general for version 8
			my $txt = $1;
			$~ = 'FORM_DETAIL_S';
			if ($magicVersion <= 599 ){
			    $it = $txt;
				pickUpCommonDisplayFields();
				$item = 'text';
				$~ = 'FORM_DETAIL_L' if (length($it) > 22);
			}
			else{
				$item = $editType;
				if ( $item !~ /(Field|Expr)/) {
					$it = $txt;
				}
				$~ = 'FORM_DETAIL_L' if (length($it) > 22);
				if ($item !~ /(Text|Field|Expr)/) {
					$~ = 'FORM_STATICS';
				}
		    }
			write;
			undef($text );
			undef($txt );
			undef($row );
			undef($col );
			undef($rows );
			undef($cols );
			undef($attr );
			undef($color );
		}
		elsif (/^PIC=/){
			if ($magicVersion >= 600){
				my $save = $_;
				chomp($_);
				readin();
				if ( !/^EXP/){
					unshift @saved, $_ ;
				}
				else{
					$save .= $_;
				}
				$_ = $save;
			}
			$pic = '';
			$hlp = '';
			$exp = '';
			$txt = '';
			$prg = '';
			$mod = '';
			$allowInput = '';
			$mst = '';
			$ctrl = '';
			$ctrlstp  = '';

			$pic = $1 if /PIC="(.+?)"/;
			$hlp = $1 if /HLP=(.+?),/;
			$exp = $1 if /EXP=(\d+)/;
			$txt = $1 if /TXT=(.+?),/;
			$prg = $1 if /PRG=(.+?),/;
			$mod = $1 if /MOD=(.+?),/;
			$inp = $1 if /INP=(.+?),/;
			$mst = $1 if /MST=(.+?)\}/;
			$ctrl = $1 if /CTRL=(.+?),/;
			$ctrl_stp = $1 if /CTRL_STP="(.+?)"/;

			if (!defined($text )) {		$text  ='';	}
			if (!defined($txt  )) {		$txt   ='';	}
			if (!defined($row  )) {		$row   ='';	}
			if (!defined($col  )) {		$col   ='';	}
			if (!defined($rows )) {		$rows  ='';	}
			if (!defined($cols )) {		$cols  ='';	}
			if (!defined($attr )) {		$attr  ='';	}
			if (!defined($color)) {		$color ='';	}

			if ($item eq 'Field') {
			}
			elsif ( $item eq 'Expr' ) {
				$it = $exp[$p][$t][$exp];
			}
			elsif ($item eq 'text') {
			}
			else{
				print "missed item\n";
			}
			$~ = 'FORM_DETAIL_S';
			$~ = 'FORM_DETAIL_L' if (length($it) > 22);
			if ($magicVersion <= 599 ){
				write;
				undef($text );
				undef($txt );
				undef($row );
				undef($col );
				undef($rows );
				undef($cols );
				undef($attr );
				undef($color );
			  }
		  }
		elsif (($name, $class)= $_ =~ /^DSP(?:_INFO)?=\{NAME="(.*?)",(?:CLSS=(\d+))?/) {
			$formNumber++;
			print "Form: $formNumber $name";
			print " Class $class" if defined($class);
			print "\n";
		}
		elsif (/^(EXP=\"|TSK|DRPD)/ || ($_ eq "PRG=\{\n")){  # there was an '=' sign on the end . Worked in Unix, Not in NT
			unshift @saved, $_ ;
			last;
		}
	}
}

sub readin
{
	$_ = shift @saved;
	if ( !defined ($_ )) {
		$_ = <IN>;
 	}
	study;
	if (!/^TSK=/) {
		$prevline = $_;
	}
	if ($_ eq "RPR=\{"){ # in report, similar to task structure, skip it.
		while (<IN>){
			if (/^PRG=/){
				last;
			}
		}
	}
#	s/ISN(_2)?=\d+,?//;  # version 8 may have optional ISN numbers we don't need.
	$_;
}
sub expandIOmode {
	($func, $val) = @_;

	if ($val eq '')	{
		$val;
		return;
	}
#	if ($func eq 'style') {
#	    if ($val &   1 )  { $val = 'style1'; }
#	    if ($val &   2 )  { $val = 'style2'; }
#	    if ($val &   4 )  { $val = 'style4'; }
#	    if ($val &   8 )  { $val = 'style8'; }
#	    if ($val &  0x10 ){ $val = 'style0x10'; }
#	    if ($val &  0x20 ){ $val = 'style0x20'; }
#	    if ($val &  0x40 ){ $val = 'style0x40'; }
#	    if ($val &  0x80 ){ $val = 'style0x80'; }
#	    if ($val &  0x100){ $val = 'style0x100'; }
#	    if ($val &  0x200){ $val = 'style0x200'; }
#	    if ($val &  0x400){ $val = 'style0x400'; }
#	    if ($val &  0x800){ $val = 'style0x800'; }
#	    if ($val &  0x1000){ $val = 'style0x1000'; }
#	    if ($val &  0x2000){ $val = 'style0x2000'; }
#	    if ($val &  0x4000){ $val = 'style0x4000'; }
#	    if ($val &  0x8000){ $val = 'style0x8000'; }
#	}
#	if ($func eq 'align') {
#	    if ($val &   1 )  { $val = 'align1'; }
#	    if ($val &   2 )  { $val = 'align2'; }
#	    if ($val &   4 )  { $val = 'align4'; }
#	    if ($val &   8 )  { $val = 'align8'; }
#	    if ($val &  0x10 ){ $val = 'align0x10'; }
#	    if ($val &  0x20 ){ $val = 'align0x20'; }
#	    if ($val &  0x40 ){ $val = 'align0x40'; }
#	    if ($val &  0x80 ){ $val = 'align0x80'; }
#	    if ($val &  0x100){ $val = 'align0x100'; }
#	    if ($val &  0x200){ $val = 'align0x200'; }
#	    if ($val &  0x400){ $val = 'align0x400'; }
#	    if ($val &  0x800){ $val = 'align0x800'; }
#	    if ($val &  0x1000){ $val = 'align0x1000'; }
#	    if ($val &  0x2000){ $val = 'align0x2000'; }
#	    if ($val &  0x4000){ $val = 'align0x4000'; }
#	    if ($val &  0x8000){ $val = 'align0x8000'; }
#	}
	elsif ($func eq 'attr') {
	    if    ($val eq 'A' ){ $val = 'Alpha'; }
	    elsif ($val eq 'N' ){ $val = 'Numeric'; }
	    elsif ($val eq 'B' ){ $val = 'Logical'; }
	    elsif ($val eq 'D' ){ $val = 'Date'; }
	    elsif ($val eq 'T' ){ $val = 'Time'; }
	    elsif ($val eq 'M' ){ $val = 'Memo'; }
	    elsif ($val eq 'I' ){ $attr = 'Image'; }
	}

	elsif ($func eq 'editControl') {
		if    ($val eq 'S') { $val = 'Static';     }#verified Staticincludes  Text, Lines, Ellipses, Rectangles
		elsif ($val eq 'E') { $val = 'Field';      }#verified
		elsif ($val eq 'P') { $val = 'Pushbutton'; }#verified
		elsif ($val eq 'T') { $val = 'Table';      }#verified
		elsif ($val eq 'C') { $val = 'CheckBox';   }#verified
		elsif ($val eq 'L') { $val = 'Slider';     }#verified
		elsif ($val eq 'O') { $val = 'OLE'; }
		elsif ($val eq 'I') { $val = 'Image'; }
		elsif ($val eq 't') { $val = 'RichText';   }
		elsif ($val eq 'R') { $val = 'Radio';      }#verified
	}
	elsif ($func eq 'mod') {
		if    ($val eq 'R') { $val = 'Read'; }
		elsif ($val eq 'W') { $val = 'Write'; }
		elsif ($val eq 'A') { $val = 'Append'; }
		elsif ($val eq 'D') { $val = 'Direct'; }
	}
	elsif ($func eq 'read') {
		if    ($val eq 'N') { $val = 'Normal'; }
		elsif ($val eq 'F') { $val = 'Fast'; }
		elsif ($val eq 'D') { $val = 'Damaged'; }
		elsif ($val eq 'R') { $val = 'Reindex'; }
	}
	elsif ($func eq 'opn') {
		if    ($val eq 'R') { $val = 'Read'; }
		elsif ($val eq 'W') { $val = 'Write'; }
		elsif ($val eq 'N') { $val = 'None'; }
	}
	elsif ($func eq 'endcheck') {
		if    ($val eq 'A') { $val = 'After'; }
		elsif ($val eq 'B') { $val = 'Before'; }
		elsif ($val eq 'I') { $val = 'Immediate'; }
	}
	elsif ($func eq 'ioformat') {
		if    ($val eq 'P') { $val = 'Page'; }
		elsif ($val eq 'L') { $val = 'Line'; }
		elsif ($val eq 'N') { $val = 'None'; }
	}
	elsif ($func eq 'iomedia') {
		if    ($val eq 'P') { $val = 'Printer'; }
		elsif ($val eq 'C') { $val = 'Console'; }
		elsif ($val eq 'S') { $val = 'Standard File'; }
		elsif ($val eq 'I') { $val = 'Internal File'; }
		elsif ($val eq 'U') { $val = 'User Driver'; }
	}
	elsif ($func eq 'eventscope') {
		if    ($val eq 'S') { $val = 'Subtree'; }
		elsif ($val eq 'T') { $val = 'Task'; }
	}
	elsif ($func eq 'eventcall') {
		if    ($val eq 'P') { $val = 'Program'; }
		elsif ($val eq 'T') { $val = 'Task'; }
	}
	$val;
}

sub	getPrgResources
{
	readin();
	die "expected RSRCE" if $_ !~ /^RSRCE/;


	while ( readin()) {
		if (/^DB/){
			$db++;
			($i) = $_ =~ /FILE=(\d+)/;
			$db[$db]->{idx} 	= $i;
			$db[$db]->{file} 	= 'None Defined';
			$db[$db]->{file} 	= expandYNexp($1) if  $_ =~ /EXP=(\d+),/;
			$db[$db]->{access}  = expandIOmode('mod', $1) if $_ =~ /MOD=(.)/;
			$db[$db]->{share}  	= expandIOmode('opn', $1) if $_ =~ /OPN=(.)/;
			$db[$db]->{'open'}  	= expandIOmode('read', $1) if $_ =~ /READ=(.)/;
#			$db[$db]->{cachesize}= $1 if $_ =~ /SIZ=(\d+)/;
		}
		elsif (/^IO/){
			$io++;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{desc}   = $1 if $_ =~ /DESC="(.*?)",/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{'format'} = $1 if $_ =~ /FRM=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{media}  = $1 if $_ =~ /STRG=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{access} = $1 if $_ =~ /MOD=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{file} = $exp[$p][$t][$1] if $_ =~ /EXP=(\d+),/;
		}
		elsif (/^EVNT=\{/) {
			$exp  = '';
			$scope='';
			$actv ='';
			$key  ='';
			$time ='';
			$mod ='' ;

			$actv  = $1 if /actv=(\d+)/;
			$key   = $1 if /KEY=(\d+)/;
			$time  = $1 if /TIME=(\d+)/;

			$scope = ($1 eq 'S')?'Subtask':'   Task' if /SCOPE=(.)/;
			$exp = $exp[$p][$t][$1] if /EXP=(\d+)/;

			$evnt[$evnt]->{key}= $key;
			$evnt[$evnt]->{actv}= $actv;
			$evnt[$evnt]->{'time'}= $time;
			$evnt[$evnt]->{'exp'}= $exp;

			$evnt[$evnt]->{scope} = $scope;

			readin();
			($mode, $task, $lock, $punct) = $_ =~ /MOD=(.),TSK=(\d+),LOCK=(.)(.)/;
			$evnt[$evnt]->{progTask}= ($mode eq 'T')?'   Task:':'Program:';

			$evnt[$evnt]->{progTaskNumber}= $task;
			$evnt[$evnt]->{lock}= $lock;
			if ($punct eq ',') {
				getArgsAndFlow();
				if (defined(@args))	{
					$i = 0;
					foreach $arg (@args){
						$evnt[$evnt]->{args}->[$i] = $arg;
						$i++;
					}
					undef(@args);
				}
			}
		    $evnt++;

		}
		elsif (/^DTLS/) {
			getDetails();
		}
		elsif (/^FLW=/) {
			doFlow();
		}
		elsif (/^DSP=/ ) {
			unshift @saved, $_ ;
			doDisplay();
		}
		elsif (/^FLD/) { #do nothing as it was all done in prescan
		}
		elsif (/^TSK=/) {
			initTaskMain();
			setHierarchicalPosition();
		}
		elsif (/^HDR=/) {
			$queryMode  = $1 if /QRY=(.),/;
			$modifyMode = $1 if /MDFY=(.),/;
			$deleteMode = $1 if /DEL=(.),/;
			$isResident = $1 if /RSDNT=(.),/;
		}
		elsif ($_ eq "PRG={\n" || /^DRPD/ ) { #dropdown menus
			unshift @saved, $_ ;
			last;
		}
	}
}
sub expandYNexp{
	my $x = shift;

	if ($x =~ /^(Y|N)$/){
		$x = $x eq 'N'?'No':'Yes';
	}
	elsif ($x =~ /(\d+)/) {
		if (defined($exp[$p][$t][$1])) {
			$x = $exp[$p][$t][$1];
		}
	}
	$x;
}
sub ynexp{
	my ( $field, $str) = @_;
	my $result = '?undefined?';

	if ($str =~ /=\{$field=(Y|N)/){
		$result = $1;
	}
	elsif ($str =~ /EXP=(\d+)/) {
		$result = $exp[$p][$t][$1];
	}
	$result;
}
sub extendYN{
	my $x = shift;

	if ($x =~ /^(Y|N)$/){
		$x = $x eq 'N'?'No':'Yes';
	}
	elsif ($x eq 'A') {
		$x = 'Ascending';
	}
	elsif ($x eq 'D') {
		$x = 'Descending';
	}
	$x;
}
format DB_DETAIL =
 @>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<  @<<<<<< @<<<<<<< @<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	$v, $db[$v]->{idx}, $dd[$db[$v]->{idx}]{desc}, $db[$v]->{access},$db[$v]->{share},$db[$v]->{'open'}, $db[$v]->{file}
.
sub dumpEvents{
    my $i;

	return if (!defined(@evnt));
	print "\nEvents:\n\n";
	print "Scope                              Program/Task     Action   Time   Expression   \n";
	print "---------------------------------------------------------------------------------\n";

	foreach $i (@evnt) {
		$mode = $i->{progTask};
		$task = $i->{progTaskNumber};

		if ($i ->{progTask} =~ /^P/ ){
			$desc = $prgtaskName[$task]->{'1'}->{desc};
		}
		else{
			$desc = $prgtaskName[$p]->{$hier . '.' . $task }->{desc};
		}

		$~ = 'EVENT_DETAIL';
		write;
		if (defined($i->{args}))	{
			$j = 1;
			foreach $arg (@{$i->{args}}){
				print "                  $j|$arg\n";
				$j++;
			}
		}
	}
	print "\n";

format EVENT_DETAIL =
@>>>>>> @>>>>>> @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>      @>>>>   @>>>>  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$i->{scope}, $i->{progTask}, $desc,           $i->{key},$i->{'time'},$i->{'exp'}
.
}
sub dumpDBfiles{
	if (!defined($db[1])){
		return;
	}
	$v = 1;
	print "\n DB Files:\n";
	print "  +-#-+Fil+---- File Name -----+Access+Share+--Open-+Exp+\n";
	while( defined($db[$v] )){
		$~ = 'DB_DETAIL';
		write;
		$v++;
	}
}
sub dumpVirtuals {

	if (!defined($virt[$p][$t][1])){
		return;
	}
	$v = 1;
	print " Virtual Fields:\n";
	print "+-#-+---- Field Name ----+Typ+-Attr--+-- Picture --+------ Range -------+\n";
	while( defined($virt[$p][$t][$v] )){
		$~ = 'VIRTUAL_DETAIL';
		write;

#		printf( "% 4d %20s % 3d %7s %s\n",
#				$v,
#				$virt[$p][$t][$v]->{desc},
#				$virt[$p][$t][$v]->{type},
#				$virt[$p][$t][$v]->{attr},
#				$virt[$p][$t][$v]->{pic}
#			  );
		$v++;
	}
}
sub	getDetails
{
	$mainFile = 0;
	$mainKey = 0;
	while (readin()) {
		if (/^KEY/) {
			$mainKey = $1 if $_ =~ /FLD=(\d)/;#does not appear if no main file
			$mainMod = $1 if $_ =~ /MOD=(.)/;
		}
		elsif (/^DB/) {
			$mainFile = $1 if $_ =~ /DB=(\d+)/;
			$mainFileDesc = $dd[$mainFile]->{desc};
		}
		elsif (/^FLW=(B|O),/) {
			($taskFlow,  $taskForceRecordDelete, $taskEndTaskCondition, $taskEndCheck ) = $_ =~ /FLW=(.),DEL=(\w+),END=(\w+),EMOD=(.),/;
			if ($taskForceRecordDelete =~ /\d+/) { $taskForceRecordDelete = $exp[$p][$t][$taskForceRecordDelete]; }
			if ($taskEndTaskCondition =~ /\d+/) { $taskEndTaskCondition = $exp[$p][$t][$taskEndTaskCondition]; }
			if ($taskFlow eq 'O' ) {
				$taskFlow = 'Online';
			}
			else {
				$taskFlow = 'Batch';
			}
		}
		elsif (/^MOD/) {
			$initialTaskMode = '?undefined?';
			if ($_ =~ /\{MOD=(.)/){
				$initialTaskMode = $initialTaskMode{$1};
			}
			elsif ($_ =~ /\{EXP=(\d+)/){
				$initialTaskMode = $exp[$p][$t][$1];
			}
		}
		elsif (/^LCT/) {
			$locateExp = 'None Defined';
			if ($_ =~ /\{EXP=(\d+)/){
				$locateExp = $exp[$p][$t][$1];
			}
			$locateDir = $1 if $_ =~ /DIR=(.)/;
			if    ($locateDir eq 'D' ) {$locateDir = 'Descending' ;}
			elsif ($locateDir eq 'A' ) {$locateDir = 'Ascending' ;}
		}
		elsif (/^RNG/) {
			$rangeExp = 'None Defined';
			if ($_ =~ /\{EXP=(\d+)/){
				$rangeExp = $exp[$p][$t][$1];
			}
			$rangeDir = $1 if  $_ =~ /DIR=(.)/;
			if    ($rangeDir eq 'D' ) {$rangeDir = 'Descending' ;}
			elsif ($rangeDir eq 'A' ) {$rangeDir = 'Ascending' ;}
		}
		elsif (/^FLG/) {
			$selectionTask 	= expandYNexp( $1 ) if $_ =~ /SLCT=(.+?),/;
			$confirmUpdate	= expandYNexp( $1 ) if $_ =~ /CNF=(.+?),/;
			$sloc  			= $1 if $_ =~ /SLOC=(.)/;
			$sfail   		= $1 if $_ =~ /SFAIL=(.)/;
			$lstrg   		= $1 if $_ =~ /LSTRG=(.)/;
			$sufix   		= $1 if $_ =~ /SUFIX=(.)/;


			if    ($sloc eq 'R' ) {$sloc = 'Retry' ;}
			elsif ($sloc eq 'A' ) {$sloc = 'Abort' ;}
			elsif ($sloc eq 'S' ) {$sloc = 'Skip'  ;}

			if    ($sfail eq 'R' ) {$sfail = 'Retry' ;}
			elsif ($sfail eq 'A' ) {$sfail = 'Abort' ;}
			elsif ($sfail eq 'S' ) {$sfail = 'Skip'  ;}

			if    ($lstrg eq 'I' ) {$lstrg = 'Immediate'; }
			elsif ($lstrg eq 'O' ) {$lstrg = 'On Modify' ;}
			elsif ($lstrg eq 'A' ) {$lstrg = 'After Modify' ;}
			elsif ($lstrg eq 'B' ) {$lstrg = 'Before Update' ;}
			elsif ($lstrg eq 'M' ) {$lstrg = 'Minimum' ;}

		}
		elsif (/^WIN/) {
			($openTaskWindow, $closeTaskWindow, $foregroundWindow, $flip) = $_ =~ /OPN=(.+?),CLS=(.+?),FGND=(.+?),FLIP=(.)/;
		}
		elsif (/^DTLS/) {
			$refreshWindow = $1 if $_ =~ /DTLS=\{RTRN=(.)/;
		}
		elsif (/^BOX/) {
		}
		elsif (/^UPD/) {
			($updateDate, $updateTime) = $_ =~ /UPD=\{DATE="(.+?)",TIME="(.+?)"/;
		}
		elsif (/^SIDE_WIN=\{/) {
			$allowOptions = 'Yes';
			$allowQuery = 'Yes';
			$allowModify = 'Yes';
			$allowCreate = 'Yes';
			$allowDelete = 'Yes';
			$allowLocate = 'Yes';
			$allowRange = 'Yes';
			$allowKeyChange = 'Yes';
			$allowSorting = 'Yes';
			$allowIOFiles = 'Yes';
			$allowCycleRecordMain = 'Yes';
			$allowReports = 'Yes';
			$allowAbort = 'Yes';
			$allowKeyOpt = 'Yes';
			$allowLocateInQuery = 'Yes';
			while (readin()) {
				if (/^WIN=\{/) {
					unshift @saved, $_ ;
					last;
				}
				else {
					$allowOptions = $1 if $_ =~ /SIDE_WIN=(N|Y)/;
					$allowQuery =   ynexp( "QRY", $_) if /^QRY/;
					$allowModify =  ynexp( "MDFY", $_ ) if /^MDFY/;
					$allowCreate =  ynexp( "CRT", $_ ) if /^CRT/;
					$allowDelete =  ynexp( "DEL", $_ ) if /^DEL/;
					$allowLocate =  ynexp( "LCT", $_ ) if /^LCT/;
					$allowRange =   ynexp( "RNG", $_ ) if /^RNG/;
					$allowKeyChange = ynexp( "KEY", $_ ) if /^KEY/;
					$allowSorting = ynexp( "SORT", $_ ) if /^SORT/;
					$allowIOFiles = ynexp( "FILE", $_ ) if /^FILE/;
					$allowCycleRecordMain = ynexp( "CYCL", $_ ) if /^CYCL/;
					$allowReports = ynexp( "RPR", $_ ) if /^RPR/;
					$allowAbort =   ynexp( "ABRT", $_ ) if /^ABRT/;
					$allowKeyOpt =  ynexp( "KOPT", $_ ) if /^KOPT/;
					$allowLocateInQuery = ynexp( "QLCT", $_ ) if /^QLCT/;
				}
			}
		}

		elsif (/^FLW=\{/) {
			$selectionTask        = extendYN( $selectionTask );
			$isResident 	      = extendYN($isResident);
			$openTaskWindow       = expandYNexp($openTaskWindow);
			$closeTaskWindow      = expandYNexp($closeTaskWindow);
			$foregroundWindow     = expandYNexp($foregroundWindow);
			$refreshWindow        = expandYNexp($refreshWindow);
			$flip                 = expandYNexp($flip);
			$allowCycleRecordMain = expandYNexp($allowCycleRecordMain);
			$confirmUpdate        = expandYNexp($confirmUpdate);
			$locateExp            = extendYN($locateExp);
			$rangeExp             = extendYN($rangeExp);
			$taskEndTaskCondition = extendYN($taskEndTaskCondition);
			$taskEndCheck = expandIOmode( 'endcheck', $taskEndCheck);
			$sufix = extendYN($sufix);
			$taskForceRecordDelete  = extendYN($taskForceRecordDelete);
			$allowOptions = extendYN($allowOptions);
			$allowModify = extendYN($allowModify);
			$allowCreate = extendYN($allowCreate);
			$allowDelete = extendYN($allowDelete);
			$allowQuery = extendYN($allowQuery);
			$allowLocate = extendYN($allowLocate);
			$allowRange = extendYN($allowRange);
			$allowKeyChange = extendYN($allowKeyChange);
			$allowSorting = extendYN($allowSorting);
			$allowIOFiles = extendYN($allowIOFiles);
			$allowAbort = extendYN($allowAbort);
			$allowKeyOpt = extendYN($allowKeyOpt);
			$allowLocateInQuery = extendYN($allowLocateInQuery);
			$allowReports = extendYN($allowReports);

			$taskName = ($hier eq '1')?$progName:$prgtaskName[$p]->{$hier}->{desc};
			if ($compatibilityMode) {
				print "\n !Last Update: $updateDate $updateTime\n\n";
 				print "Task Name: $taskName\n";
			}
			else {
 				print "\nTask Name: $taskName \tLast Update: $updateDate $updateTime\n";
			}
			if ($mainFile == 0 ) {
				$fileDesc = '';
				$keyDesc = '';
			}
			else {
				$fileDesc = $dd[$mainFile]->{desc};
				if ($mainKey == 0 ) {
					$keyDesc = '';
				}
				else {
					$keyDesc = $dd[$mainFile]->{key}->[$mainKey];
				}
			}
			print <<"TASKTOP";
--------------------------------------------------
                Main File: $mainFile. $fileDesc   Key: $mainKey. $keyDesc
                Task Type: $taskFlow
             Initial Mode: $initialTaskMode
          Selection Table: $selectionTask
            Resident Task: $isResident

 //Task Control

         Open Task Window: $openTaskWindow
        Close Task Window: $closeTaskWindow
        Foreground Window: $foregroundWindow
      Refresh Task Window: $refreshWindow

      Flip Field on Input: $flip
        Cycle Record Main: $allowCycleRecordMain
           Confirm Update: $confirmUpdate
             Form Records: 0

               Locate Exp: $locateExp
             Locate Order: $locateDir

                Range Exp: $rangeExp
              Range Order: $rangeDir
                 End Task: $taskEndTaskCondition
                End Check: $taskEndCheck
      Force Record Suffix: $sufix
      Force Record Delete: $taskForceRecordDelete

         Locking Strategy: $lstrg
         On Locked Record: $sloc
  On Failed Record Access: $sfail

 //Options Control

            Allow Options: $allowOptions
             Allow Modify: $allowModify
             Allow Create: $allowCreate
             Allow Delete: $allowDelete
              Allow Query: $allowQuery
             Allow Locate: $allowLocate
              Allow Range: $allowRange
         Allow Key Change: $allowKeyChange
            Allow Sorting: $allowSorting
          Allow I/O Files: $allowIOFiles
              Allow Abort: $allowAbort
   Allow Key Optimization: $allowKeyOpt
    Allow Locate in Query: $allowLocateInQuery
            Allow Reports: $allowReports

TASKTOP

            if ($hier eq '1'){
                print <<"RIGHTS";
              Query Right: $queryRight
             Modify Right: $modifyRight
           Deletion Right: $deleteRight
          Execution Right: $executeRight

RIGHTS
				printTaskHierarchy($p);
			}
			print "//Task Levels\n\n";


			dumpVirtuals();
			dumpEvents();
			dumpDBfiles();
	        unshift @saved, $_;
			last;
		}
	}
}
sub initTaskMain{
	$t++;
	$evnt = 0;
	undef @evnt;
	$io = 0;
	$db = 0;
	undef @db;
}
sub writeProgram
{
	$p++;
	$t=0;
	initTaskMain();
	$hier='1';
	$mainFile = 'None';

	readin();

	die "expected HDR" if $_ !~ /^HDR/;

	$progName = $1 if /DESC="(.+?)"/;
	print STDOUT ".... $p. $progName\n" if $opt_v;
	$queryRight   = 'Not defined';
	$modifyRight  = 'Not defined';
	$deleteRight  = 'Not defined';
	$executeRight = 'Not defined';

	$queryRight   = rights($1) if /QRY=(\d+)/;
	$modifyRight  = rights($1) if /MDFY=(\d+)/;
	$deleteRight  = rights($1) if /DEL=(\d+)/;
	$executeRight = rights($1) if /EXE=(\d+)/;

	$isResident = $1 if /RSDNT=(.),/;

	# replace characters prohibited in file names with hyphens so epsilon can write a file name
	# replace spaces so epsilon is not confused when creating buffer names
	$progName =~ tr/\\\/?*:<>% /-/;
	$prgNumber = $opt_n?(sprintf("%03d",$p)):'';

	$outfile = "z$prgNumber-$progName.ezr";

	open( OUT, "> $outfile" );
	select OUT;
	$startSecs = time;
	
	if ($os eq 'Windows_NT'){
		$date = `date /t` . ' ' .`time /t`;
	}
	else{
		$date = `date`;
	}	
	print "mgtrans: Magic Source Translation - Version $mgMajorVers.$mgMinorVers $versionDate by Ira Gershenhorn w\\Perl $] \n\n" ;
	print " Program: $progName \t\t$date\n\n" ;

	$indentLevel = 1;
	$indentLevelPrev = 1;
	@indentExp =();
	getPrgResources();
	$elapsed = time - $startSecs;
	print "\n ***Elapsed Time for $progName: $elapsed seconds\n\n";
	undef $exp[$p];
	close OUT;
}
sub	getArgsAndFlow {
	$orig = $_;
	undef @args;
	while (1){
		readin();
		if ( $magicVersion <= 599 && /^EXP=(\d+)/ ||
			 $magicVersion >= 600 && /^ARG=\{EXP=(\d+)/ 
		   ){
			my $tmp = $exp[$p][$t][$1];
			if ($tmp =~ /\'([A-Z]+)\'VAR/) {
				$tmp = '@' . varDesc($1);
			}
			push @args, $tmp;
		}
		elsif ( $magicVersion <= 599 && /^ARG="(\w+)"/ ||
			 $magicVersion >= 600 && /ARG=\{VAR="(\w+)"/
		   ){
			push @args, varDesc($1);
		}
		else{
			unshift @saved, $_;
			last;
		}
		if (/FLW=\{/){
			chomp($orig);
			$_ = $orig . $_;
			last;
		}
	}
}

format VIRTUAL_DETAIL =
 @>>>> @<<<<<<<<<<<<<<<<<<<< @>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $v,	$virt[$p][$t][$v]->{desc},	$virt[$p][$t][$v]->{type}, $virt[$p][$t][$v]->{attr}, $virt[$p][$t][$v]->{pic}, $virt[$p][$t][$v]->{range}
.

sub readPrgList{
    my $file = shift;
    my $p = 1;

    open ( PRG, "< $file ");
    while (<PRG>){
		if (/\d+:\d+/){
			s/^\0x0c//;
			$_ =~ /^(.+)\d\d\/\d\d\//;
			$prgtaskName[$p]->{'1'}->{desc} = $1;
			$p++;
		}
    }
    close PRG;
}
sub printSubTree{
	my ($pp, $phier) = @_;

	$phier .= '.1';
	while ( defined(	$prgtaskName[$pp]->{$phier}->{desc})){
		$dots = $phier =~ tr/\./\./;#count em
		print  substr( $tabstr, 0, $dots+1), "$prgtaskName[$pp]->{$phier}->{desc}\n";
		printSubTree($pp, $phier);
		$phier =~ s/(\d+)$/$1+1/e;  #Try the next one
	}
}
sub printTaskHierarchy {
	my $pp = shift;

	if (defined($prgtaskName[$pp]->{'1.1'}->{desc})){
		print "\nTask Hierarchy:";
		print "\n------------------------------------------------------------\n";
		print "\n\t$progName\n";

		printSubTree($pp, '1');
		print "\n------------------------------------------------------------\n";
	}
}


sub usage{
   pod2usage( { -message => "\n" . $0 . ": ". $error . "\n\n" . $copyrightLine ,
				-exitval => 1  ,  
				-verbose => 0  
				 } );
}
sub detailedUsage{
   pod2usage( { -message => $copyrightLine ,
				-exitval => 0  ,  
				-verbose => 1,
				-output => \*STDOUT
				 } );
}
sub manpage{
   pod2usage( { -message => $copyrightLine ,
				-exitval => 0  ,  
				-verbose => 2,
				-output => \*STDOUT
				 } );
}
sub read_mgtrans_ini{
	my $path = $1 if $file =~ /(^.*\/)/;
	my $ini = $path . 'mgtrans.ini';
	if (-f $ini){
		open INI, "< $ini";
		while (<INI>) {
			if (/^(\w+)\s*=\s*([^ ]+)/)	{
				$ini{lc($1)}=$2;
			}
		}
		close INI;
	}
}

